﻿using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Resources;
using System.Xml.Linq;

namespace Objectware.Silverlight.Testing.TestProject
{
	public class AssemblyLoadEventArgs : EventArgs
	{
		public Assembly Assembly { get; set; }
		
	}

	public static class SubApplicationHelper
	{
		public static void LoadTestAssemblyFromXapAsync(string xapName, EventHandler<AssemblyLoadEventArgs> callback)
		{
			WebClient client = new WebClient();
			
			client.OpenReadCompleted += (sender, e) =>
			                            	{
			                            		var sri = new StreamResourceInfo(e.Result, null);
			                            		var sri2 = Application.GetResourceStream(sri,
			                            		                                         new Uri("AppManifest.xaml", UriKind.Relative));
			                            		var streamReader = new StreamReader(sri2.Stream);
			                            		var xaml = streamReader.ReadToEnd();
			                            		XDocument document = XDocument.Parse(xaml);
			                            		XElement root = document.Root;
												if (null != root)
												{
													Assembly entryAssembly = null;

													var entryPoint = root.Attribute("EntryPointAssembly").Value;
													var partsElement = root.FirstNode as XElement;
													if( null != partsElement )
													{
														var parts = from p in partsElement.Elements()
																	select p.Attribute("Source").Value;

														foreach (var part in parts)
														{
															AssemblyPart assemblyPart = new AssemblyPart();
															assemblyPart.Source = part;

															StreamResourceInfo info = Application.GetResourceStream(
																new StreamResourceInfo(e.Result, "application/binary"),
																new Uri(assemblyPart.Source, UriKind.Relative));

															var asm = assemblyPart.Load(info.Stream);
															if( part.Contains(entryPoint) )
															{
																entryAssembly = asm;
															}
														}
													}

													callback(client, new AssemblyLoadEventArgs { Assembly = entryAssembly });
												}
			                            	};

			client.OpenReadAsync(new Uri(xapName, UriKind.Relative));
		}

		public static Application GetElementFromXap(string xapName, string type)
		{
			Application element = null;
			bool loaded = false;
			WebClient	client = new WebClient();
			client.OpenReadCompleted += (sender, e) =>
			                            	{
												
			                            		string dll = Path.GetFileNameWithoutExtension(xapName) + ".dll";
												try
												{
													element = LoadElementFromXap(dll, type, e.Result);
												}
												finally
												{
													loaded = true;
												}
			                            	};
			client.OpenReadAsync(new Uri(xapName,UriKind.Relative));
			while (!loaded) ;

			return element;
		}

		public static Application LoadElementFromXap(string dllFile, string type, Stream stream)
		{




			string manifest = new StreamReader(
				Application.GetResourceStream(
					new StreamResourceInfo(
						stream, null),
					new Uri("AppManifest.xaml", UriKind.Relative)).Stream).ReadToEnd();

			Deployment deployment = XamlReader.Load(manifest) as Deployment;

			Assembly asm = null;
			foreach (AssemblyPart part in deployment.Parts)
			{
				StreamResourceInfo info = Application.GetResourceStream(
					new StreamResourceInfo(stream, "application/binary"),
					new Uri(part.Source, UriKind.Relative));

				if (part.Source == dllFile)
				{
					asm = part.Load(info.Stream);
				}
				else
				{
					part.Load(info.Stream);
				}
			}

			if (null != asm)
			{
				Type uiType = (from t in asm.GetTypes()
						   where t.Name.Contains(type)
				           select t).Single();
				if( null != uiType )
				{
					Application element = asm.CreateInstance(uiType.FullName) as Application;
					return element;
				}
			}
			return null;
			
		}
	}
}